import React, { useEffect, useState } from "react";
import { useStyles } from "./style";
import { ArrowItem, IntrusionItem, Item, ItemCol } from "./component";
import { AttackPhaseProps, AttackPhaseType } from "./type";
import classnames from "classnames";

enum LegendsKey {
  UNBROKEN = "unbroken",
  BROKEN = "broken",
}

const DEFAULT_SELECTED_PHASES = [
  AttackPhaseType.Recon,
  AttackPhaseType.Delivery,
  AttackPhaseType.Intrusion_Broken,
  AttackPhaseType.Intrusion_Unbroken,
  AttackPhaseType.Control,
  AttackPhaseType.Goal,
  AttackPhaseType.Lateral,
];

export const BROKEN_PHASES = [
  AttackPhaseType.Intrusion_Broken,
  AttackPhaseType.Control,
  AttackPhaseType.Goal,
  AttackPhaseType.Lateral,
];

const UNBROKEN_PHASES = [
  AttackPhaseType.Recon,
  AttackPhaseType.Delivery,
  AttackPhaseType.Intrusion_Unbroken,
];

const DEFAULT_PHASE_NAMES = {
  recon: "侦查",
  delivery: "载荷投递",
  intrusion: "入侵",
  control: "命令与控制",
  lateral: "内网横向",
  goal: "达成目标",
};

const isEqual = (a: string[], b: string[]) =>
  a.length === b.length && a.sort().toString() === b.sort().toString();

AttackPhase.allAttackPhases = DEFAULT_SELECTED_PHASES;

AttackPhase.unbrokenAttackPhases = UNBROKEN_PHASES;

AttackPhase.brokenAttackPhases = BROKEN_PHASES;

function AttackPhase({
  phaseCount,
  phaseNames = DEFAULT_PHASE_NAMES,
  value = [],
  onChange,
  className,
  legendVisible = true,
  legendBrokenName = "已失陷",
  legendUnbrokenName = "未失陷",
  popoverVisible = false,
  onPopoverJump,
}: AttackPhaseProps) {
  const classes = useStyles();
  const intrusionUnbroken = AttackPhaseType.Intrusion_Unbroken;
  const intrusionBroken = AttackPhaseType.Intrusion_Broken;
  const [isAll, isUnbrokenPhase, isBrokePhase] = [
    isEqual(value, DEFAULT_SELECTED_PHASES),
    isEqual(value, UNBROKEN_PHASES),
    isEqual(value, BROKEN_PHASES),
  ];
  const legendsValue: {
    unbroken?: boolean;
    broken?: boolean;
  } = {
    unbroken: isAll || isUnbrokenPhase,
    broken: isAll || isBrokePhase,
  };

  const legends = [
    { label: legendUnbrokenName, value: LegendsKey.UNBROKEN },
    { label: legendBrokenName, value: LegendsKey.BROKEN },
  ];

  const handlePhaseClick = (type: AttackPhaseType) => {
    if (!onChange) {
      return;
    }
    let updatePhases = [...value];
    const idx = updatePhases.indexOf(type);
    if (idx > -1) {
      updatePhases.splice(idx, 1);
    } else {
      updatePhases.push(type);
    }
    const { unbroken, broken } = legendsValue;
    if (unbroken && !updatePhases.includes(intrusionBroken)) {
      updatePhases.push(intrusionBroken);
    }
    if (broken && !updatePhases.includes(intrusionUnbroken)) {
      updatePhases.push(intrusionUnbroken);
    }
    onChange?.(updatePhases);
  };

  const handleIntrusionPhaseClick = () => {
    if (!onChange) {
      return;
    }
    const isSelected =
      value?.includes(intrusionUnbroken) && value?.includes(intrusionBroken);
    const updatePhases = isSelected
      ? [...value].filter(
          (p) => p !== intrusionBroken && p !== intrusionUnbroken
        )
      : [...value].concat([intrusionBroken, intrusionUnbroken]);
    onChange?.(updatePhases);
  };

  const handleLegendClick = (legendKey: LegendsKey) => {
    if (!onChange) {
      return;
    }
    const updateLegendsValue = {
      ...legendsValue,
      [legendKey]: !legendsValue?.[legendKey],
    };
    const { unbroken, broken } = updateLegendsValue;
    if (unbroken && broken) {
      onChange?.([...DEFAULT_SELECTED_PHASES]);
      return;
    }
    if (unbroken || broken) {
      onChange?.(broken ? [...BROKEN_PHASES] : [...UNBROKEN_PHASES], broken);
      return;
    }
    onChange?.([]);
  };

  const itemBasicProps = {
    phases: value,
    onClick: handlePhaseClick,
    popoverVisible,
    onPopoverJump,
  };
  return (
    <div className={classes.chartTriggerContainer}>
      {legendVisible && (
        <div className={classes.chartLegend}>
          {legends.map((l, idx) => {
            const classValue =
              l.value === LegendsKey.BROKEN && legendsValue?.[l.value]
                ? classes.legendBroken
                : l.value === LegendsKey.UNBROKEN && legendsValue?.[l.value]
                ? classes.legendUnbroken
                : "";
            const hasClickFun = !!onChange;
            return (
              <span
                key={idx}
                className={classnames(
                  (classes.legend, hasClickFun && classes.withPointer)
                )}
                onClick={() => handleLegendClick(l.value)}
              >
                <span className={classnames(classes.legendMark, classValue)} />
                {l.label}
              </span>
            );
          })}
        </div>
      )}
      <div className={classnames(classes.chartContainer, className)}>
        <ItemCol classname={classes.largeCol}>
          <Item
            name={phaseNames?.recon ?? DEFAULT_PHASE_NAMES.recon}
            count={phaseCount?.recon ?? 0}
            type={AttackPhaseType.Recon}
            {...itemBasicProps}
          />
        </ItemCol>
        <ItemCol classname={classes.largeCol}>
          <ArrowItem />
          <Item
            name={phaseNames?.delivery ?? DEFAULT_PHASE_NAMES.delivery}
            count={phaseCount?.delivery ?? 0}
            type={AttackPhaseType.Delivery}
            {...itemBasicProps}
          />
        </ItemCol>
        <ItemCol>
          <IntrusionItem
            name={phaseNames?.intrusion ?? DEFAULT_PHASE_NAMES.intrusion}
            count={phaseCount?.intrusion ?? 0}
            {...itemBasicProps}
            onClick={handleIntrusionPhaseClick}
          />
          <ArrowItem />
        </ItemCol>
        <ItemCol>
          <ArrowItem classname={classes.itemRotate} isBroken />
        </ItemCol>
        <ItemCol classname={classes.colJustifyEnd}>
          <Item
            name={phaseNames?.control ?? DEFAULT_PHASE_NAMES.control}
            count={phaseCount?.control ?? 0}
            type={AttackPhaseType.Control}
            {...itemBasicProps}
          />
        </ItemCol>
        <ItemCol>
          <ArrowItem classname={classes.itemRotateNegative} isBroken />
        </ItemCol>
        <ItemCol>
          <Item
            name={phaseNames?.lateral ?? DEFAULT_PHASE_NAMES.lateral}
            count={phaseCount?.lateral ?? 0}
            type={AttackPhaseType.Lateral}
            {...itemBasicProps}
          />
          <ArrowItem isBroken />
        </ItemCol>
        <ItemCol>
          <ArrowItem classname={classes.itemRotate} isBroken />
        </ItemCol>
        <ItemCol classname={classes.colJustifyEnd}>
          <Item
            name={phaseNames?.goal ?? DEFAULT_PHASE_NAMES.goal}
            count={phaseCount?.goal ?? 0}
            type={AttackPhaseType.Goal}
            {...itemBasicProps}
          />
        </ItemCol>
      </div>
    </div>
  );
}

export default AttackPhase;
